#!/usr/bin/env python
"""
Command - Execute a command and capture stdout & stderr; compare to expected

License: BSD
Project homepage: http://skaffold.sf.net
"""

import subprocess
import traceback
import skaffold

def default_exitcode_validation(details):
    if details['Exit code']!=0: 
        raise skaffold.Failure("Exit code is nonzero (exitcode==%d)" % details['Exit code'])
        
def default_stderr_validation(details):
    if len(details['stderr']): 
        raise skaffold.Failure("stderr is not empty")
        
class Command:
    def __init__(self, visitor, command=None, args=None, check_exitcode=None, check_stdout=None, check_stderr=None):
        self.visitor = visitor
        self.command = command
        self.args = args if args else []
        self.check_stdout =   check_stdout   if check_stdout   else lambda nul: None
        self.check_exitcode = check_exitcode if check_exitcode else default_exitcode_validation
        self.check_stderr =   check_stderr   if check_stderr   else default_stderr_validation
        if not isinstance(command,basestring):
            raise TypeError("program is not a string type (given %s instead)" % type(command))
        if type(args) is not list:
            raise TypeError("args is not a list (given %s instead)" % type(args))

    def validate(self):
        self.check_exitcode(self.details)
        self.check_stderr(self.details)
        self.check_stdout(self.details)
                    
    def run(self):
        self.details = skaffold.Result.Details('')

        try:
            cmd = [self.command]+self.args
            process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        except OSError, e:
            result = skaffold.Error("Error executing program '%s'" % " ".join(cmd), self.details)
            result.traceback = traceback.format_exc()
            raise result
            
        self.details['Exit code'] = process.wait()
        self.details['stdout'] = process.stdout.read()
        self.details['stderr'] = process.stderr.read()
        try:
            self.validate()
        except skaffold.Result, e:
            e.attach_details(self.details)
            raise e
        else:
            raise skaffold.Success('', self.details)